package org.itark.bbs.common.aop;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * controller请求日志
 */
@Slf4j
@Aspect
@Component
public class TraceAspect {
    private static final int CALL_TIME_LONG = 10000;

    /**
     * 拦截controller
     */
    @Around("execution(public * org.itark.bbs..controller..*(..))")
    public Object controllerAround(ProceedingJoinPoint pjp) throws Throwable {
        Long startTime = System.currentTimeMillis();
        String methodName = pjp.getSignature().getName();
        String className = pjp.getTarget().getClass().getName();
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String queryStr = request.getQueryString();
        String url = request.getServletPath();
        Map parameterMap = request.getParameterMap();
        String token = request.getHeader("token");
        String params = "";
        String contentType = request.getContentType();
        String method = request.getMethod();
        if (token != null) {
            token = "token=" + request.getHeader("Authorization");
        }
        try {
            Object[] args = pjp.getArgs();
            log.info("请求方法:{}.{}", className, methodName);
            ServletInputStream servletInputStream = request.getInputStream();
            if (!CollUtil.isEmpty(parameterMap)) {
                params = JSONUtil.toJsonStr(request.getParameterMap());
            } else {
                params = IOUtils.toString(servletInputStream, "utf-8").replaceAll("\\s+", " ");
            }
            log.info("\nmethod: {};\nurl: {};\ntoken: {};\ncontentType: {};\nparams: {}", method, url, token, contentType, params);
            Object retVal = pjp.proceed(args);
            return retVal;
        } catch (Throwable e) {
            throw e;
        } finally {
            Long timeDiff = System.currentTimeMillis() - startTime;
            if (timeDiff >= CALL_TIME_LONG) {
                log.error("请求响应耗时过长:{}ms, url:{};", timeDiff, url);
            }
            log.info("方法:{}.{} 执行完成, 请求耗时:{}ms", className, methodName, timeDiff);
        }
    }

}
